// 安全滚动到页面顶部的工具方法
// 兼容 window、document.documentElement、document.body 三种主流场景
// 支持平滑滚动和立即滚动，自动降级处理
// 用法：import { scrollToTop } from '@/utils/scroll-util'
//       scrollToTop() 或 scrollToTop({ behavior: 'smooth' })

// 滚动选项类型定义
export interface ScrollToOptions {
  behavior?: 'auto' | 'smooth'
  onComplete?: () => void // 滚动完成回调
  onError?: (error: Error) => void // 错误回调
}

// 缓存环境检测结果，避免重复检测
let _supportsSmoothScroll: boolean | null = null
let _hasWindow: boolean | null = null
let _hasDocument: boolean | null = null
let _scrollContainer: HTMLElement | null = null

/**
 * 检测浏览器是否支持平滑滚动
 */
function supportsSmoothScroll(): boolean {
  if (_supportsSmoothScroll !== null) return _supportsSmoothScroll

  try {
    // 检测是否支持 scroll-behavior CSS 属性
    const testElement = document.createElement('div')
    testElement.style.scrollBehavior = 'smooth'
    _supportsSmoothScroll = testElement.style.scrollBehavior === 'smooth'
  } catch {
    _supportsSmoothScroll = false
  }

  return _supportsSmoothScroll
}

/**
 * 检测运行环境
 */
function hasWindow(): boolean {
  if (_hasWindow !== null) return _hasWindow
  _hasWindow = typeof window !== 'undefined' && typeof window.scrollTo === 'function'
  return _hasWindow
}

function hasDocument(): boolean {
  if (_hasDocument !== null) return _hasDocument
  _hasDocument = typeof document !== 'undefined'
  return _hasDocument
}

/**
 * 检测真正的滚动容器
 */
function getScrollContainer(): HTMLElement | null {
  if (_scrollContainer !== null) return _scrollContainer

  if (!hasDocument()) return null

  // 检测哪个元素真正控制页面滚动
  const html = document.documentElement
  const body = document.body

  if (!html || !body) return null

  // 保存原始滚动位置
  const originalScrollTop = getCurrentScrollTop()

  try {
    // 测试方法：尝试滚动看哪个元素真正起作用
    const testScrollTop = 1

    // 测试 documentElement
    html.scrollTop = testScrollTop
    if (html.scrollTop === testScrollTop) {
      html.scrollTop = originalScrollTop // 恢复原始位置
      _scrollContainer = html
      return html
    }

    // 测试 body
    body.scrollTop = testScrollTop
    if (body.scrollTop === testScrollTop) {
      body.scrollTop = originalScrollTop // 恢复原始位置
      _scrollContainer = body
      return body
    }

    // 都不行，默认返回 html
    _scrollContainer = html
    return html
  } catch (error) {
    console.warn('检测滚动容器失败:', error)
    _scrollContainer = html
    return html
  }
}

/**
 * 获取当前滚动位置
 */
function getCurrentScrollTop(): number {
  if (!hasDocument()) return 0

  return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
}

/**
 * 设置滚动位置
 */
function setScrollTop(value: number): void {
  if (!hasDocument()) return

  const scrollContainer = getScrollContainer()

  // 优先使用检测到的滚动容器
  if (scrollContainer) {
    scrollContainer.scrollTop = value
  }

  // 为了兼容性，也尝试其他方法
  if (hasWindow()) {
    try {
      window.scrollTo(0, value)
    } catch (error) {
      console.warn('window.scrollTo 失败:', error)
    }
  }

  // 确保其他可能的滚动容器也被设置
  if (document.documentElement && document.documentElement !== scrollContainer) {
    document.documentElement.scrollTop = value
  }

  if (document.body && document.body !== scrollContainer) {
    document.body.scrollTop = value
  }
}

/**
 * 检测 window.scrollTo 是否有效
 */
function isWindowScrollToEffective(): boolean {
  if (!hasWindow()) return false

  const originalScrollTop = getCurrentScrollTop()
  const testScrollTop = originalScrollTop + 1

  try {
    window.scrollTo(0, testScrollTop)
    const newScrollTop = getCurrentScrollTop()

    // 恢复原始位置
    window.scrollTo(0, originalScrollTop)

    return Math.abs(newScrollTop - testScrollTop) < 1
  } catch {
    return false
  }
}

/**
 * 使用原生方法平滑滚动
 */
function nativeSmoothScrollTo(top: number, options?: ScrollToOptions): boolean {
  if (!hasWindow() || !supportsSmoothScroll()) return false

  try {
    // 检测 window.scrollTo 是否有效
    if (isWindowScrollToEffective()) {
      window.scrollTo({
        top,
        behavior: 'smooth',
      })

      // 监听滚动完成
      if (options?.onComplete) {
        const checkComplete = () => {
          if (Math.abs(getCurrentScrollTop() - top) <= 1) {
            options.onComplete?.()
          } else {
            requestAnimationFrame(checkComplete)
          }
        }
        requestAnimationFrame(checkComplete)
      }

      return true
    }

    // window.scrollTo 无效，尝试直接在滚动容器上使用 scrollTo
    const scrollContainer = getScrollContainer()
    if (scrollContainer && 'scrollTo' in scrollContainer) {
      // 使用类型断言，因为HTMLElement可能有scrollTo方法
      const scrollableElement = scrollContainer as HTMLElement & {
        scrollTo: (options: { top: number; behavior: 'smooth' | 'auto' }) => void
      }
      scrollableElement.scrollTo({
        top,
        behavior: 'smooth',
      })

      // 监听滚动完成
      if (options?.onComplete) {
        const checkComplete = () => {
          if (Math.abs(getCurrentScrollTop() - top) <= 1) {
            options.onComplete?.()
          } else {
            requestAnimationFrame(checkComplete)
          }
        }
        requestAnimationFrame(checkComplete)
      }

      return true
    }

    return false
  } catch (error) {
    console.warn('原生平滑滚动失败:', error)
    return false
  }
}

/**
 * 使用 requestAnimationFrame 实现平滑滚动到顶部
 */
function smoothScrollToTopFallback(options?: ScrollToOptions): void {
  let startTime: number | null = null
  const startPosition = getCurrentScrollTop()
  const duration = 500 // 动画持续时间（毫秒）

  function animate(currentTime: number): void {
    if (startTime === null) startTime = currentTime

    const timeElapsed = currentTime - startTime
    const progress = Math.min(timeElapsed / duration, 1)

    // 使用缓动函数（easeOutCubic）
    const easeProgress = 1 - Math.pow(1 - progress, 3)
    const currentPosition = startPosition * (1 - easeProgress)

    setScrollTop(currentPosition)

    if (progress < 1) {
      requestAnimationFrame(animate)
    } else {
      // 确保最终位置为0
      setScrollTop(0)
      options?.onComplete?.()
    }
  }

  try {
    requestAnimationFrame(animate)
  } catch (error) {
    // 降级到立即滚动
    setScrollTop(0)
    options?.onError?.(error as Error)
  }
}

/**
 * 滚动到页面顶部
 * @param options 滚动选项
 */
export function scrollToTop(options?: ScrollToOptions): void {
  const { behavior = 'auto', onComplete, onError } = options || {}

  try {
    // 如果不需要平滑滚动，直接设置位置
    if (behavior === 'auto') {
      setScrollTop(0)
      onComplete?.()
      return
    }

    // 需要平滑滚动时，优先使用原生方法
    if (nativeSmoothScrollTo(0, options)) {
      return
    }

    // 使用自定义平滑滚动降级方案
    smoothScrollToTopFallback(options)
  } catch (error) {
    console.error('滚动到顶部失败:', error)
    // 最后的降级方案：立即滚动
    setScrollTop(0)
    onError?.(error as Error)
  }
}

/**
 * 滚动到指定位置
 * @param top 目标位置
 * @param options 滚动选项
 */
export function scrollToPosition(top: number, options?: ScrollToOptions): void {
  const { behavior = 'auto', onComplete, onError } = options || {}

  try {
    if (behavior === 'auto') {
      setScrollTop(top)
      onComplete?.()
      return
    }

    // 需要平滑滚动时，优先使用原生方法
    if (nativeSmoothScrollTo(top, options)) {
      return
    }

    // 使用自定义平滑滚动降级方案
    smoothScrollToPosition(top, options)
  } catch (error) {
    console.error('滚动到指定位置失败:', error)
    setScrollTop(top)
    onError?.(error as Error)
  }
}

/**
 * 使用 requestAnimationFrame 实现平滑滚动到指定位置
 */
function smoothScrollToPosition(targetPosition: number, options?: ScrollToOptions): void {
  let startTime: number | null = null
  const startPosition = getCurrentScrollTop()
  const distance = targetPosition - startPosition
  const duration = 500

  function animate(currentTime: number): void {
    if (startTime === null) startTime = currentTime

    const timeElapsed = currentTime - startTime
    const progress = Math.min(timeElapsed / duration, 1)

    // 使用缓动函数（easeOutCubic）
    const easeProgress = 1 - Math.pow(1 - progress, 3)
    const currentPosition = startPosition + distance * easeProgress

    setScrollTop(currentPosition)

    if (progress < 1) {
      requestAnimationFrame(animate)
    } else {
      setScrollTop(targetPosition)
      options?.onComplete?.()
    }
  }

  try {
    requestAnimationFrame(animate)
  } catch (error) {
    setScrollTop(targetPosition)
    options?.onError?.(error as Error)
  }
}

/**
 * 重置缓存（用于测试或特殊场景）
 */
export function resetScrollUtilCache(): void {
  _supportsSmoothScroll = null
  _hasWindow = null
  _hasDocument = null
  _scrollContainer = null
}
